/*
 * =====================================================================================
 *
 *       Filename:  Observer.cpp
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2015年02月01日 15时28分27秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  LiuYi (), swliuyi@gmail.com
 *   Organization:  
 *
 * =====================================================================================
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <limits.h>
#include <iostream>
#include <set>
#include  <tr1/memory>

using namespace std;

class Observer
{
    protected:
        string observerState;
        string name;
    public:
        Observer(string n=""):name(n){}
        string GetState() const
        {
            return observerState;
        }
        void SetState(string s)
        {
            observerState = s;
        }
        virtual void Update() = 0;
};

class Subject
{
    private:
        set<Observer*> observers;
        string subjectState;
    public:
        void SetState(string s)
        {
            subjectState = s;
        }
        string GetState() const
        {
            return subjectState;
        }
        void Attach(Observer * ob)
        {
            observers.insert(ob);
        }
        void Detach(Observer * ob)
        {
            observers.erase(ob);
        }
        void Notify()
        {
            for( set<Observer *>::iterator it = observers.begin() ; it != observers.end() ; it++ )
            {
                (*it)->Update();
            }
        }
};

class ConcreteSubject : public Subject
{
};

class ConcreteObserver: public Observer
{
    private:
        Subject * subject;
    public:
        ConcreteObserver(string n = "", Subject * sub=NULL):Observer(n), subject(sub){}
        void Update()
        {
            SetState(subject->GetState());
            cout<<subject->GetState()<<" "<<name<<" 状态为"<<GetState()<<endl;
        }
};

int main(int argc, char *argv[])
{
    tr1::shared_ptr<ConcreteSubject> cos1(new ConcreteSubject());
    tr1::shared_ptr<ConcreteObserver> cob1(new ConcreteObserver("man1", cos1.get()));
    tr1::shared_ptr<ConcreteObserver> cob2(new ConcreteObserver("man2", cos1.get()));
    cos1->Attach(cob1.get());
    cos1->Attach(cob2.get());


    cos1->SetState("first news comming");
    cos1->Notify();

    cos1->SetState("second news comming");
    cos1->Notify();
}
